/*
 * @Author       : Wei.Studio
 * @Date         : 2023-01-30 10:45:50
 * @LastEditors: WeiStudio
 * @LastEditTime: 2023-02-03 14:12:05
 * @FilePath     : \qesf\apps\unit-test\utest.c
 * @Description  : 
 * 
 * Copyright (c) 2022 by Wei.Studio, All Rights Reserved. 
 */



#include "utest.h"
#include <getopt.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>


QELOG_DOMAIN("utest");

static int utest_random_int(int min, int max)
{
    static qe_bool init = qe_false;

    if (init == qe_false) {
        time_t now;
        srand(time(&now));
        init = qe_true;
    }

    return rand() % max + min;
}

static void utest_file2buffer(const char *file, void *buf, int len)
{
    FILE *fp;

    fp = fopen(file, "rb");
    if (!fp)
        return;
    
    fread(buf, len, 1, fp);
    fclose(fp);
}

static void utest_buffer2file(const char *file, void *buf, int len)
{
    FILE *fp;

    fp = fopen(file, "wb");
    if (!fp)
        return;
    
    fwrite(buf, len, 1, fp);
    fclose(fp);    
}

static int fibonacci(int n)
{
	if ((n==1) || (n==2)) {
		return 1;
	}

	return fibonacci(n-1) + fibonacci(n-2);
}

static void utest_fibonacci(int n)
{
	int x = fibonacci(n);
	ut_info("fibonacci in:%d out:%d", n, x);
}

static void utest_array_1d_to_2d(void)
{
#define UTEST_BUFSZ 128
#define UTEST_DIM   16
    int i, j;
    int x = 16;
    char *buffer, (*p)[x];

    buffer = qe_malloc(UTEST_BUFSZ);
    p = (char (*)[x])buffer;

    for (i=0; i<UTEST_BUFSZ; i++) {
        buffer[i] = i;
    }

    qe_hexdump_debug(buffer, UTEST_BUFSZ);

    ut_debug("buffer:0x%x", buffer);

    for (i=0; i<4; i++) {
        for (j=0; j<4; j++) {
            ut_debug("p[%d][%d]:0x%x 0x%x", i, j, &p[i][j], p[i][j]);
            //ut_debug("p[%d][%d]", i, j);
        }
    }

    qe_free(buffer);
    ut_debug("exit");
#undef UTEST_BUFSZ
#undef UTEST_DIM
}

static void utest_stringbuilder(void)
{
#define UTEST_BUFSZ 64
    char buffer[UTEST_BUFSZ];

    qe_memset(buffer, 0x0, UTEST_BUFSZ);
    qe_strb sbd = qe_strb_init(buffer, UTEST_BUFSZ);

    qe_strb_string(sbd, "Hello");
    ut_info("string:%.*s", sbd.len, sbd.head);

    qe_strb_string(sbd, " World.");
    ut_info("string:%.*s", sbd.len, sbd.head);

    qe_strb_format(sbd, "This is year %d", 20);
    ut_info("string:%.*s", sbd.len, sbd.head);

    qe_strb_int(sbd, 23);
    ut_info("string:%.*s", sbd.len, sbd.head);

    ut_debug("string len:%d", sbd.len);
    qe_strb_format(sbd, " 01/30, aaaaaaaaaaaaaaaaaaaaaaaaaab");
    ut_info("string:%.*s", sbd.len, sbd.head);
    ut_debug("string len:%d", sbd.len);

    qe_memset(buffer, 0x0, UTEST_BUFSZ);
    sbd = qe_strb_frombuf(buffer, UTEST_BUFSZ);
    qe_strb_string(sbd, "Next string");
    ut_info("string:%.*s", sbd.len, sbd.head);

#undef UTEST_BUFSZ
}

static void utest_ringbuffer_once(qe_ringbuffer *rb)
{
    int i;
    unsigned len;
    char rbuf[32];

	char *strings[] = {
		"AAAAA\r\n",
        "123456\r\n",
		"BBBBBBB\r\n",
        "12345678\r\n",
		"CCCCCCCCC\r\n",
        "1234567891\r\n",
		"DDDDDDDDDDD\r\n",
        "123456789123\r\n",
        "EEEEEEEEEEEEE\r\n",
        "12345678912345\r\n",
        "FFFFFFFFFFFFFFF\r\n",
        "1234567891234567\r\n",
        "GGGGGGGGGGGGGGGGG\r\n",
        "123456789123456789\r\n",
        "HHHHHHHHHHHHHHHHHHH\r\n",
		"12345678912345678912\r\n",
	};

    ut_info("ring capacity:%d free:%d wait:%d", 
        qe_ringbuffer_capacity(rb),
        qe_ringbuffer_freesize(rb),
        qe_ringbuffer_wait(rb));

    for (i=0; i<qe_array_size(strings); i++) {
        qe_ringbuffer_write(rb, strings[i], qe_strlen(strings[i]));
        ut_info("ring write strings[%d] %d", i, qe_strlen(strings[i]));
        ut_debug("string[i]:", i);
        qe_hexdump_debug(strings[i], qe_strlen(strings[i]));
        ut_debug("ring buffer count:%d:", rb->count);
        qe_hexdump_debug(rb->buf, rb->size);
    }

    ut_info("ring[0]:0x%x", qe_ringbuffer_index(rb, 0));
    ut_info("ring[%d]:0x%x", qe_ringbuffer_wait(rb)-1,
        qe_ringbuffer_index(rb, qe_ringbuffer_wait(rb)-1));

    ut_info("ring capacity:%d free:%d wait:%d", 
        qe_ringbuffer_capacity(rb),
        qe_ringbuffer_freesize(rb),
        qe_ringbuffer_wait(rb));

    qe_ringbuffer_read(rb, rbuf, sizeof(rbuf));
    ut_info("ring read %d", sizeof(rbuf));
    ut_debug("ring read:");
    qe_hexdump_debug(rbuf, sizeof(rbuf));

    ut_info("ring[0]:0x%x", qe_ringbuffer_index(rb, 0));
    ut_info("ring[%d]:0x%x", qe_ringbuffer_wait(rb)-1,
        qe_ringbuffer_index(rb, qe_ringbuffer_wait(rb)-1));

    ut_info("ring capacity:%d free:%d wait:%d",
        qe_ringbuffer_capacity(rb),
        qe_ringbuffer_freesize(rb),
        qe_ringbuffer_wait(rb));

    qe_ringbuffer_clear(rb);

    ut_info("ring capacity:%d free:%d wait:%d", 
        qe_ringbuffer_capacity(rb),
        qe_ringbuffer_freesize(rb),
        qe_ringbuffer_wait(rb));
}

static void utest_ringbuffer_destroy(qe_ptr data)
{
    qe_ringbuffer *rb = (qe_ringbuffer *)data;
    ut_info("destroy ringbuffer %p %p", rb, rb->buf);
    qe_free(rb->buf);
}

static void utest_ringbuffer(void)
{
#define UTEST_BUFSZ 128
    char buffer[UTEST_BUFSZ];
    char *dbuf;
    qe_ringbuffer rb_exb_static;
    qe_ringbuffer rb_exb_dynamic;
    qe_ringbuffer *rb_dynamic;

    /**
     * Initialize RingBuffer with a static buffer
     */
    ut_info("init ring with external static buffer %d", UTEST_BUFSZ);
    qe_memset(buffer, 0x0, UTEST_BUFSZ);
    qe_ringbuffer_init(&rb_exb_static, buffer, UTEST_BUFSZ);
    utest_ringbuffer_once(&rb_exb_static);
    qe_ringbuffer_destroy(&rb_exb_static);

    /**
     * Initialize RingBuffer with a dynamic buffer
     */
    dbuf = qe_malloc(UTEST_BUFSZ);
    ut_info("init ring with external dynamic buffer %d %p %p", 
        UTEST_BUFSZ, &rb_exb_dynamic, dbuf);
    qe_ringbuffer_init_full(&rb_exb_dynamic, dbuf, UTEST_BUFSZ, 
        utest_ringbuffer_destroy);
    utest_ringbuffer_once(&rb_exb_dynamic);
    qe_ringbuffer_destroy(&rb_exb_dynamic);

    /**
     * Create a RingBuffer
     */
    ut_info("init ring with new %d", UTEST_BUFSZ);
    rb_dynamic = qe_ringbuffer_new(UTEST_BUFSZ);
    if (!rb_dynamic) {
        ut_error("ringbuffer(%dbytes) create fail", UTEST_BUFSZ);
        return;
    }
    utest_ringbuffer_once(rb_dynamic);
    qe_ringbuffer_destroy(rb_dynamic);

#undef UTEST_BUFSZ
}

static void utest_ringqueue(void)
{
#define UTEST_DATA_NUM  8
    int i;
    int a, b, c, d, e, v;
    int data[UTEST_DATA_NUM];
    qe_ringq ring, *pring;

    a = 1;
    b = 2;
    c = 3;
    d = 4;
    e = 5;

    ut_info("Step1: RingQueue static init and enq/deq");

    qe_ringq_init(&ring, data, sizeof(int), UTEST_DATA_NUM);

    ut_debug("num:%d", qe_ringq_wait(&ring));
    qe_ringq_enq(&ring, &a, 1);
    qe_ringq_enq(&ring, &a, 1);
    qe_ringq_enq(&ring, &b, 1);
    qe_ringq_enq(&ring, &b, 1);
    qe_ringq_enq(&ring, &c, 1);
    qe_ringq_enq(&ring, &c, 1);
    qe_ringq_enq(&ring, &d, 1);
    qe_ringq_enq(&ring, &d, 1);
    qe_ringq_enq(&ring, &e, 1);
    qe_ringq_enq(&ring, &e, 1);

    ut_debug("num:%d", qe_ringq_wait(&ring));
    int size = qe_ringq_wait(&ring);
    for (i=0; i<size; i++) {
        qe_ringq_deq(&ring, &v, 1);
        ut_debug("ring[%d]:%d", i, v);
    }
    ut_debug("num:%d", qe_ringq_wait(&ring));
    ut_info("Step1 finish");

    ut_info("Step2: RingQueue dynamic init from array");
    pring = qe_ringq_create(sizeof(int), UTEST_DATA_NUM);
    for (i=0; i<UTEST_DATA_NUM; i++) {
        data[i] = i;
    }
    ut_debug("num:%d", qe_ringq_wait(pring));
    qe_ringq_enq(pring, data, UTEST_DATA_NUM);
    qe_ringq_enq(pring, &e, 1);
    qe_ringq_enq(pring, &e, 1);
    ut_debug("num:%d", qe_ringq_wait(pring));
    size = qe_ringq_wait(pring);
    for (i=0; i<size; i++) {
        qe_ringq_deq(pring, &v, 1);
        ut_debug("ring[%d]:%d", i, v);
    }
    ut_info("Step2 finish");

    ut_info("Step3: RingQueue static init from array");
    qe_ringq ring2;
    for (i=0; i<UTEST_DATA_NUM; i++) {
        data[i] = i;
    }
    qe_ringq_fromarray(&ring2, data, sizeof(int), UTEST_DATA_NUM);
    ut_debug("num:%d", qe_ringq_wait(&ring2));
    qe_ringq_enq(&ring2, &e, 1);
    qe_ringq_enq(&ring2, &e, 1);
    size = qe_ringq_wait(&ring2);
    for (i=0; i<size; i++) {
        qe_ringq_deq(&ring2, &v, 1);
        ut_debug("ring[%d]:%d", i, v);
    }
    ut_info("Step3 finish");

#undef UTEST_DATA_NUM
}

static void utest_minpq(void)
{
    ut_info("MinPQ Testing");
}

static void utest_queue(void)
{
#define UTEST_DATA_NUM  8
    int i;
    int size;
    int data[UTEST_DATA_NUM];
    int v1, v2, v3, v4, v5, vx;
    qe_ret ret;
    
    v1 = 1;
    v2 = 2;
    v3 = 3;
    v4 = 4;
    v5 = 5;

    ut_info("Queue Testing");

    ut_info("Step1> Create queue use qe_queue_new()");
    qe_queue *p_queue;
    p_queue = qe_queue_new(int, UTEST_DATA_NUM);
    ut_debug("queue size:%d", qe_queue_wait(p_queue));
    ut_debug("enqueue:%d ret:%d", v1, qe_queue_enq(p_queue, &v1));
    ut_debug("enqueue:%d ret:%d", v1, qe_queue_enq(p_queue, &v1));
    ut_debug("enqueue:%d ret:%d", v2, qe_queue_enq(p_queue, &v2));
    ut_debug("enqueue:%d ret:%d", v2, qe_queue_enq(p_queue, &v2));
    ut_debug("enqueue:%d ret:%d", v3, qe_queue_enq(p_queue, &v3));
    ut_debug("enqueue:%d ret:%d", v3, qe_queue_enq(p_queue, &v3));
    ut_debug("enqueue:%d ret:%d", v4, qe_queue_enq(p_queue, &v4));
    ut_debug("enqueue:%d ret:%d", v4, qe_queue_enq(p_queue, &v4));
    ut_debug("queue size:%d", qe_queue_wait(p_queue));
    ut_debug("enqueue:%d ret:%d", v5, qe_queue_enq(p_queue, &v5));
    ut_debug("queue size:%d", qe_queue_wait(p_queue));
    size = qe_queue_wait(p_queue);
    for (i=0; i<size; i++) {
        qe_queue_deq(p_queue, &vx);
        ut_debug("dequeue:%d", vx);
    }
    qe_free(p_queue);
    p_queue = QE_NULL;
    ut_info("Step1> finish");


    ut_info("Step2> Initialize queue from array");
    qe_queue queue;
    qe_memset(&queue, 0x0, sizeof(qe_queue));
    for (i=0; i<UTEST_DATA_NUM; i++) {
        data[i] = i;
    }
    qe_queue_init(&queue, data, sizeof(int), UTEST_DATA_NUM, UTEST_DATA_NUM);
    ut_debug("queue size:%d", qe_queue_wait(&queue));
    ut_debug("enqueue:%d ret:%d", v5, qe_queue_enq(&queue, &v5));
    size = qe_queue_wait(&queue);
    for (i=0; i<size; i++) {
        qe_queue_deq(&queue, &vx);
        ut_debug("dequeue %d", i);
    }
    ut_info("Step2> finish");


    ut_info("Step3> Initialize ringq from array");
    qe_memset(&queue, 0x0, sizeof(qe_queue));
    qe_queue_init(&queue, data, sizeof(int), UTEST_DATA_NUM, UTEST_DATA_NUM);
    ut_debug("queue size:%d", qe_queue_wait(&queue));
    ut_debug("enqueue:%d ret:%d", v5, qe_queue_enq(&queue, &v5));
    for (i=0; i<size; i++) {
        qe_queue_deq(&queue, &vx);
        ut_debug("dequeue %d", vx);
    }
    ut_info("Step3> finish");
}

static void utest_bitmap(void)
{
    qe_bitmap_init(bitmap, 64);
    qe_bitmap_zero(bitmap, 64);

    qe_bitdump_debug(bitmap, 64);
    qe_set_bit(13, bitmap);
    ut_info("set bit[13]");
    qe_bitdump_debug(bitmap, 64);
    qe_clear_bit(13, bitmap);
    ut_info("clear bit[13]");
    qe_change_bit(14, bitmap);
    ut_info("change bit[14]");
    qe_bitdump_debug(bitmap, 64);
    
    qe_bitmap *map = qe_bitmap_new(64);
    qe_bitmap_zero(map, 64);
    qe_set_bit(27, map);
    ut_info("set bit[27]");
    qe_bitdump_debug(map, 64);
    qe_clear_bit(27, map);
    ut_info("clear bit[27]");
    qe_bitdump_debug(map, 64);
    qe_change_bit(29, map);
    ut_info("change bit[29]");
    qe_bitdump_debug(map, 64);
    qe_free(map);
}

int array_int_compare(const void *a, const void *b)
{
    int *v1 = (int *)a;
    int *v2 = (int *)b;

    if (*v1 < *v2)
        return -1;
    else if (*v1 == *v2)
        return 0;
    else
        return 1;
}

static void utest_array_test(void)
{
    int a[] = {1,3,5,7};
    int b[] = {23,13,45};

    qe_array *array = qe_array_new(sizeof(int));
    if (!array) {
        ut_error("create array error");
        return;
    }

    qe_array_append(array, (const void *)a, qe_array_size(a));
    for (int i=0; i<array->len; i++) {
        ut_debug("array[%d] %d", i, qe_array_index(array, int, i));
    }

    qe_array_prepend(array, (const void *)b, qe_array_size(b));

    for (int i=0; i<array->len; i++) {
        ut_debug("array[%d] %d", i, qe_array_index(array, int, i));
    }

    qe_array_sort(array, array_int_compare);

    for (int i=0; i<array->len; i++) {
        ut_debug("array[%d] %d", i, qe_array_index(array, int, i));
    }

    qe_array_free(array, qe_true);
}

static void rollfile_test_hook(const char *name)
{
    ut_debug("%s will remove", name);
}

#if defined(CONFIG_ROLLING_FILE)
static void rolling_file_test(void)
{
    int i;
#define ROLL_TEST_NUM   4096

    qe_rollingfile *rollfile = qe_rollingfile_new(
        ".", "test", "txt", 4, 1024);

    if (!rollfile) {
        ut_error("create rollingfile error");
        return;
    }

    qe_rollingfile_set_hook(rollfile, QE_ROLLINGFILE_HOOK_BEFORE_REMOVE, rollfile_test_hook);

    for (i=0; i<ROLL_TEST_NUM; i++) {
        usleep(200000);
        qe_rollingfile_append_string(rollfile, 
            "RollingFileTesting...............................................\n");
    }

    qe_rollingfile_free(rollfile);

#undef ROLL_TEST_NUM
}
#endif

static void qe_string_test(void)
{
    /* memory test */
    // for (int i=0; i<50000; i++) {
    //     qe_string *string = qe_string_new("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
    //     qe_string_append(string, "worldworldworldworldworldworldworldworldworld\
    //         worldworldworldworldworldworldworldworldworldworldworldworldworld");
    //     qe_string_prepend(string, "hello hello hello hello hello hello hello hello hello ");
    //     qe_string_free(string, qe_true);
    //     qe_sleep(200);
    // }

    qe_string *string = qe_string_new("hello world");
    ut_debug("string %s", string->str);
    qe_string_erase(string, 0, 6);
    ut_debug("string %s", string->str);
    qe_string_prepend(string, "hello ");
    ut_debug("string %s", string->str);
    qe_string_format(string, "my name is");
    ut_debug("string %s", string->str);
    qe_string_append_format(string, "aaa");
    ut_debug("string %s", string->str);
    qe_string_replace(string, "aaa", "bbb", 0);
    ut_debug("string %s", string->str);
    qe_string_free(string, qe_true);

    ut_debug("qe_base size %d", sizeof(qe_ubase));
    ut_debug("void * %d", sizeof(void *));
    ut_debug("int:%d long:%d", sizeof(int), sizeof(long));
}

static void qe_list_test(void)
{
    qe_list *node;
    QE_LIST_INIT(test);

    typedef struct
    {
        int v;
        qe_list list;
    }test_item;

    test_item a, b, *p;
    a.v = 1;
    b.v = 2;

    qe_list_append(&a.list, &test);
    qe_list_append(&b.list, &test);

    qe_list_foreach(node, &test) {
        p = qe_list_entry(node, test_item, list);
        ut_debug("%d", p->v);
    }
}

static void gb2312_utf8_convert(void)
{
    char *str = "01\n02\n03\n04\n05\n06\n07\n08\n09\n10\n11\n12";
    int data[12];
    char buf[128];
    sscanf(str, "%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d\n%d", 
        &data[0], &data[1], &data[2], &data[3], 
        &data[4], &data[5], &data[6], &data[7], 
        &data[8], &data[9], &data[10], &data[11]);
    ut_debug("data %d %d %d %d %d %d %d %d %d %d %d %d", 
        data[0], data[1], data[2], data[3], data[4], data[5],
        data[6], data[7], data[8], data[9], data[10], data[11]);
    sprintf(buf, "%02i\n%02i\n%02i\n%02i\n%02i\n%02i\n%02i\n%02i\n%02i\n%02i\n%02i\n%02i", 
        data[0], data[1], data[2], data[3], 
        data[4], data[5], data[6], data[7],
        data[8], data[9], data[10], data[11]);
    ut_debug("buf %s", buf);
}

static void binpkg_test(char *file_path)
{
    int i;
    int n;
    char *buf;
    FILE *fp;
    qe_ret ret;
    qe_binpkg_header hdr;
    qe_array *sections;
    qe_binpkg_section sec;

    ut_info("pointer size %d long %d long long %d", sizeof(sections), sizeof(long), sizeof(long long));

    fp = fopen(file_path, "rb");
    if (!fp) {
        ut_error("file %s open error");
        return;
    }

    n = fread(&hdr, 1, sizeof(hdr), fp);
    if (n != sizeof(hdr)) {
        ut_error("read hdr error");
        fclose(fp);
        return;
    }

    sections = qe_array_new(sizeof(qe_binpkg_section));
    n = qe_binpkg_get_sectab_size(&hdr);
    ut_info("sectab size %d", n);
    buf = qe_malloc(n);
    fread(buf, 1, n, fp);

    qe_binpkg_parse(&hdr, buf, sections);

    ut_info("magic        : 0x%x", hdr.magic);
    ut_info("num sections : %d", hdr.num_sections);

    for (i=0; i<sections->len; i++) {
        sec = qe_array_index(sections, qe_binpkg_section, i);
        ut_info("section[%d]   : %d 0x%x %d", i, sec.tag, sec.offset, sec.size);
    }

    qe_array_free(sections, qe_true);
    fclose(fp);
}

static qe_hashtab *hash_subfunc_init(void)
{
    int i;
    qe_u32 x = 45;
    char *name = "subfunc";
    qe_hashtab *htab = qe_hashtab_new(qe_str_hash, qe_str_equal);
    qe_hashtab_insert(htab, "x", &x);
    qe_hashtab_insert(htab, "name", name);
    for (i=0; i<100; i++) {
        x++;
    }
    return htab;
}

static void hash_subfunc_look(qe_hashtab *xtab)
{
    int i;
    qe_u32 *x;
    char *name;

    for (i=0; i<100; i++) {
        x++;
    }
   
    x = qe_hashtab_lookup(xtab, "x");
    name = qe_hashtab_lookup(xtab, "name");
    ut_debug("x:%d %p", *x, x);
    ut_debug("name:%s %p", name, name);
}

static void hash_test(void)
{
    qe_u32 number;
    qe_s32 temp;
    char *name = "XXXAVDC";
    qe_u32 *pnum;
    qe_s32 *ptmp;
    char *pname;
    qe_ptr key, val;
    qe_hashtab_iter iter;

    qelog_set_handler("hash", QELOG_DEBUG, QE_NULL);

    qe_hashtab *htab = qe_hashtab_new(qe_str_hash, qe_str_equal);
    if (!htab) {
        ut_error("hash table create error");
        return;
    }

    number = 25;
    temp = -18;
    qe_hashtab_insert(htab, "number", &number);
    ut_info("insert number:%d", number);
    qe_hashtab_insert(htab, "temp", &temp);
    ut_info("insert temp:%d", temp);
    qe_hashtab_insert(htab, "name", name);
    ut_info("insert name:%s", name);

    pnum = qe_hashtab_lookup(htab, "number");
    ut_info("lookup number:%d", *pnum);
    ptmp = qe_hashtab_lookup(htab, "temp");
    ut_info("lookup temp:%d", *ptmp);
    pname = qe_hashtab_lookup(htab, "name");
    ut_info("lookup name:%s", pname);

    qe_hashtab_iter_init(&iter, htab);

    while (qe_hashtab_iter_next(&iter, &key,&val)) {
        ut_info("key:%s val:%p", key, val);
    }

    qe_hashtab_destroy(htab);
    ut_info("hash table destroy");

    qe_hashtab *xtab = hash_subfunc_init();
    pnum = qe_hashtab_lookup(xtab, "x");
    pname = qe_hashtab_lookup(xtab, "name");
    ut_info("lookup x:%d %p", *pnum, pnum);
    ut_info("lookup name:%s %p", pname, pname);
    hash_subfunc_look(xtab);
    qe_hashtab_destroy(xtab);
}

static void usage(void)
{
    printf("\n");
    printf("utest <cmd> <opt>\n");
    printf("  -h,?,--help          print help information\n");
    printf("  --loglevel           set log level(0~5)\n");
    printf("  --fibonacci <num>    do fibonacci with param\n");
    printf("  --stringbuilder      string builder test\n");
    printf("  --ringbuffer         ring buffer test\n");
    printf("  --ringqueue          ring queue test\n");
    printf("  --minpq              minpq test\n");
    printf("  --queue              queue test\n");
    printf("  --bitmap             bitmap test\n");
    printf("  --gbuf               gbuf test\n");
    printf("  --gbufpool           gbuf pool test\n");
#if defined(CONFIG_ROLLING_FILE)
    printf("  --rollingfile        rollingfile test\n");
#endif
    printf("  --string             qe string test\n");
    printf("  --array              qe array test\n");
    printf("  --qelist             qe list test\n");
    printf("  --bpkg               qe binpkg test\n");
    printf("  --hash               qe hashtab test\n");
    printf("\n");
}

int main(int argc, char **argv)
{
    int opt;
    qe_u8  loglevel;
    qe_u32 param_u32;
    char *bptab_filepath = QE_NULL;

    qelog_init(QELOG_DEBUG, 
        QELOG_FUNC|QELOG_LV|QELOG_DM|QELOG_CL);
    qelog_set_handler(QELOG_DOMAIN_HEX, QELOG_DEBUG, QE_NULL);

    static const struct option long_opts[] = {
        {"help",              no_argument,       NULL,  arg_help},
        {"loglevel",	      required_argument, NULL,  arg_loglevel},
        {"fibonacci",	      required_argument, NULL,  arg_fibonacci},
        {"array-1d22d",       no_argument,       NULL,  arg_array_1d22d},
        {"strbuilder",        no_argument,       NULL,  arg_stringbuilder},
        {"ringbuffer",	      no_argument,	     NULL,  arg_ringbuffer},
        {"ringqueue",         no_argument,       NULL,  arg_ringqueue},
        {"minpq",             no_argument,       NULL,  arg_minpq},
        {"queue",             no_argument,       NULL,  arg_queue},
        {"bitmap",            no_argument,       NULL,  arg_bitmap},
        {"gbuf",              no_argument,       NULL,  arg_gbuf},
        {"gbufpool",          no_argument,       NULL,  arg_gbuf_pool},
        {"array",             no_argument,       NULL,  arg_array_test},
#if defined(CONFIG_ROLLING_FILE)
        {"rollingfile",       no_argument,       NULL,  arg_rolling_file},
#endif
        {"string",            no_argument,       NULL,  arg_qestring},
        {"list",              no_argument,       NULL,  arg_list_test},
        {"gb2312utf8",        no_argument,       NULL,  arg_gb2312_utf8},
        {"bpkg",              required_argument, NULL,  arg_bpkg_test},
        {"hash",              no_argument,       NULL,  arg_hash_test},
        {NULL, 0, NULL, 0}
    };

    while ((opt = getopt_long(argc, argv, "?h-", long_opts, NULL)) != -1)
    {
        switch (opt)
        {
            case 'h':
            case '?':
            case arg_help:
            default:
                usage();
                exit(EXIT_SUCCESS);

            case arg_loglevel:
                loglevel = atoi(optarg);
                printf("loglevel:%d\n", loglevel);
                qelog_set_level(loglevel);
                break;
            
            case arg_fibonacci:
                utest_fibonacci(atoi(optarg));
                break;

            case arg_array_1d22d:
                utest_array_1d_to_2d();
                break;

            case arg_stringbuilder:
                utest_stringbuilder();
                break;

            case arg_ringbuffer:
                utest_ringbuffer();
                break;

            case arg_ringqueue:
                utest_ringqueue();
                break;

            case arg_minpq:
                utest_minpq();
                break;

            case arg_queue:
                utest_queue();
                break;

            case arg_bitmap:
                utest_bitmap();
                break;

            case arg_array_test:
                utest_array_test();
                break;

#if defined(CONFIG_ROLLING_FILE)
            case arg_rolling_file:
                rolling_file_test();
                break;
#endif

            case arg_qestring:
                qe_string_test();
                break;

            case arg_list_test:
                qe_list_test();
                break;

            case arg_gb2312_utf8:
                gb2312_utf8_convert();
                break;

            case arg_bpkg_test:
                binpkg_test(optarg);
                break;

            case arg_hash_test:
                hash_test();
                break;
        }
    }
    
    exit(EXIT_SUCCESS);
}